package com.dm.cloud.oauthlib.conf;

import cn.hutool.core.util.StrUtil;
import com.dm.cloud.core.config.CommonConstants;
import com.dm.cloud.core.exception.CustomAuthException;
import com.dm.cloud.core.exception.CustomAuthPermissionException;
import com.dm.cloud.core.mode.UserMode;
import com.dm.cloud.core.service.user.CurrentUserService;
import com.dm.cloud.core.util.RequsetArrtibutesUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.server.PathContainer;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.pattern.PathPatternParser;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class AuthInteceptor implements HandlerInterceptor {

    private CurrentUserService currentUserService;

    private String servletContextPath;

    /**
     * 必须要认证的url
     */
    private List<String> hasLoginUrls=new ArrayList<>();

    /**
     * 排除认证的url
     */
    private List<String> ignoreLoginUrls=new ArrayList<>();

    /**
     * 需要授权的配置
     */
    private List<PermissionConf> permissionConfs=new ArrayList<>();

    /**
     * 需要授权的配置
     */
    private List<RoleConf> roleConfs=new ArrayList<>();

    public AuthInteceptor(CurrentUserService currentUserService,String servletContextPath){
        this.currentUserService=currentUserService;
        this.servletContextPath=servletContextPath;
    }

    /**
     * 添加login拦截url
     * @param url
     * @return
     */
    public AuthInteceptor hasLogin(String url){
        if(StrUtil.isNotEmpty(url)){
            this.hasLoginUrls.add(url);
        }
        return this;
    }

    /**
     * 排除的登录login
     * @param url
     * @return
     */
    public AuthInteceptor ignoreLogin(String url){
        if(StrUtil.isNotEmpty(url)){
            this.ignoreLoginUrls.add(url);
        }
        return this;
    }

    /**
     * 添加permission拦截url
     * @param url
     * @param permissions
     * @return
     */
    public AuthInteceptor hasPermission(String url,String... permissions ){
        if(StrUtil.isNotEmpty(url) && permissions!=null && permissions.length>0){
            this.permissionConfs.add(PermissionConf.builder()
                    .permisionUrls(url)
                    .permisions(Arrays.asList(permissions))
                    .build());
        }
        return this;
    }

    /**
     * 添加角色拦截url
     * @param url
     * @param roles
     * @return
     */
    public AuthInteceptor hasRole(String url,String... roles ){
        if(StrUtil.isNotEmpty(url) && roles!=null && roles.length>0){
            this.roleConfs.add(RoleConf.builder()
                    .roleUrls(url)
                    .roles(Arrays.asList(roles))
                    .build());
        }
        return this;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String uri = request.getRequestURI();
        if(StrUtil.isNotEmpty(servletContextPath) && uri.startsWith(servletContextPath)){
            uri=uri.substring(servletContextPath.length());
        }
        //排除的url
        if(handleIgnoreLogin(uri)){
            return true;
        }
        //必须登录的url
        handleLogin(uri);
        //必须有权限的url
        handlePermission(uri);
        //必须有角色的
        handleRole(uri);
        return true;
    }

    private void handlePermission(String uri){
        if(permissionConfs.isEmpty()){
            return;
        }
        for (PermissionConf permissionConf : permissionConfs) {
            if(new PathPatternParser()
                    .parse(permissionConf.permisionUrls)
                    .matches(PathContainer.parsePath(uri))){
                if(StrUtil.isEmpty(RequsetArrtibutesUtil.get(CommonConstants.AUTH_HEAD_KEY))){
                    throw new CustomAuthException("用户未登录，请登录！");
                }
                if(!currentUserService.hasPermissions(permissionConf.permisions.toArray(new String[permissionConf.permisions.size()]))){
                    throw new CustomAuthPermissionException("当前用户无权限");
                }
            }
        }
    }

    /**
     * 验证角色
     * @param uri
     */
    private void handleRole(String uri){
        for (RoleConf roleConf : roleConfs) {
            if(new PathPatternParser()
                    .parse(roleConf.roleUrls)
                    .matches(PathContainer.parsePath(uri))){
                if(StrUtil.isEmpty(RequsetArrtibutesUtil.get(CommonConstants.AUTH_HEAD_KEY))){
                    throw new CustomAuthException("用户未登录，请登录！");
                }
                UserMode user = currentUserService.getCurrentUser();
                if(currentUserService.hasRoles(roleConf.getRoles().toArray(new String[roleConf.getRoles().size()]))){
                    throw new CustomAuthPermissionException("当前角色无权限");
                }
                RequsetArrtibutesUtil.put(CommonConstants.AUTH_USER_DETAIL, user);
                return;
            }
        }
    }

    /**
     * 验证登录
     * @param uri
     */
    private void handleLogin(String uri){
        for (String hasLoginUrl : hasLoginUrls) {
            if(new PathPatternParser()
                    .parse(hasLoginUrl)
                    .matches(PathContainer.parsePath(uri))){
                if(StrUtil.isEmpty(RequsetArrtibutesUtil.get(CommonConstants.AUTH_HEAD_KEY))){
                    throw new CustomAuthException("用户未登录，请登录！");
                }
                UserMode user = currentUserService.getCurrentUser();
                RequsetArrtibutesUtil.put(CommonConstants.AUTH_USER_DETAIL, user);
                return;
            }
        }
    }

    /**
     * 验证排除的url
     * @param uri
     * @return
     */
    private boolean handleIgnoreLogin(String uri){
        for (String ignoreLoginUrl : ignoreLoginUrls) {
            if(new PathPatternParser()
                    .parse(ignoreLoginUrl)
                    .matches(PathContainer.parsePath(uri))){
                return true;
            }
        }
        return false;
    }

    @Builder
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class RoleConf{

        /**
         * 需要验证角色的url
         */
        private String roleUrls;

        /**
         * 需要验证的角色
         */
        private List<String> roles;

    }

    @Builder
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class PermissionConf{

        /**
         * 需要验证权限的url
         */
        private String permisionUrls;

        /**
         * 需要验证的权限项
         */
        private List<String> permisions;

    }

}
